﻿Imports PowerSong.SongDatabase.Legacy.Items

''' <summary>
''' Represents a list of songs stored in the currently active PowerSong database.
''' </summary>
Public Class Songs

    Friend FDatabase As Database = Nothing
    Friend FSongsData As Data.SongsDataTable = Nothing
    Friend FCategoriesData As Data.SongCategoriesDataTable = Nothing

    Friend Sub New(ByVal database As Database)

        FDatabase = database
        FSongsData = database.Data.Songs
        FCategoriesData = database.Data.SongCategories

    End Sub

    ''' <summary>
    ''' Returns all of the song IDs for all of the songs contained in the database.
    ''' </summary>
    ''' <returns>A list of song IDs.</returns>
    Public Function GetAllSongIDs() As List(Of Guid)

        Dim Result As New List(Of Guid)
        For Each Row As Data.SongsRow In FSongsData
            Result.Add(Row.SongID)
        Next
        Return Result

    End Function

    ''' <summary>
    ''' Returns all of the song IDs for all of the songs contained in the database assigned to the given category.
    ''' </summary>
    ''' <param name="categoryID">The ID of the category whose songs to retrieve.</param>
    ''' <returns>A list of song IDs.</returns>
    Public Function GetCategorySongIDs(ByVal categoryID As Guid) As List(Of Guid)

        Dim Result As New List(Of Guid)
        For Each Row As Data.SongsRow In FSongsData
            For Each Category As Data.SongCategoriesRow In Row.GetSongCategoriesRows
                If Category.CategoryID = categoryID Then Result.Add(Row.SongID)
            Next
        Next
        Return Result

    End Function

    ''' <summary>
    ''' Gets the title for all of the songs contained in the database.
    ''' </summary>
    ''' <returns>The title of every song in the database.</returns>
    Public Function GetAllSongTitles() As List(Of String)

        Dim Result As New List(Of String)
        For Each Row As Data.SongsRow In FSongsData
            Result.Add(Row.Title)
        Next
        Return Result

    End Function

    ''' <summary>
    ''' Gets all of the file names of every song contained in the database.
    ''' </summary>
    ''' <returns>The short file name of every song in the database (ie: [guid].song...).</returns>
    Public Function GetAllSongFileNames() As List(Of String)

        Dim Result As New List(Of String)
        For Each Row As Data.SongsRow In FSongsData
            Result.Add(Row.SongID.ToString + ".song")
        Next
        Return Result

    End Function

    ''' <summary>
    ''' Gets the details for a song, based on its title.
    ''' </summary>
    ''' <param name="songTitle">The title of the song to retrieve.</param>
    ''' <returns>The requested song, based on its title.</returns>
    Public Function GetSong(ByVal songTitle As String) As SongItem

        songTitle = songTitle.ToUpper.Trim
        For Each Row As Data.SongsRow In FSongsData
            If Row.Title.ToUpper.Trim = songTitle Then

                ' Get the filename of the song
                Dim SongFileName As String = GetSongFilename(Row.SongID)

                ' Return the song
                Dim Result As SongItem = SongItem.Load(SongFileName)
                AddCategoriesToSong(Result)
                Return Result

            End If
        Next
        Throw New ApplicationException("Cannot find the song with title '" + songTitle + "'.")

    End Function

    ''' <summary>
    ''' Gets the details for a song, based on its ID.
    ''' </summary>
    ''' <param name="songID">The ID of the song to retrieve.</param>
    ''' <returns>The requested song, based on its ID.</returns>
    Public Function GetSong(ByVal songID As Guid) As SongItem

        Dim Result As SongItem = SongItem.Load(GetSongFilename(songID))
        AddCategoriesToSong(Result)
        Return Result

    End Function

    ''' <summary>
    ''' Gets the song title, based on its ID.
    ''' </summary>
    ''' <param name="songID">The song ID.</param>
    ''' <returns>The song title.</returns>
    Public Function GetSongTitle(ByVal songID As Guid) As String

        ' Try to find the song title based on the given song ID
        Dim Row As Data.SongsRow = FSongsData.FindBySongID(songID)
        If Row IsNot Nothing AndAlso Row.SongID = songID Then Return Row.Title

        ' The song could not be found
        Throw New ApplicationException("Cannot find song.")

    End Function

    ''' <summary>
    ''' Gets the list of song categories assigned to the given song.
    ''' </summary>
    ''' <param name="songID">The song ID whose categories to retrieve.</param>
    ''' <returns>The list of category IDs assigned to the given song.</returns>
    Public Function GetSongCategories(ByVal songID As Guid) As List(Of Guid)

        Dim Result As New List(Of Guid)
        For Each Category As Data.SongCategoriesRow In FCategoriesData
            If Category.SongID = songID Then
                Result.Add(Category.CategoryID)
            End If
        Next
        Return Result

    End Function

    ''' <summary>
    ''' Adds the given song to the database.
    ''' </summary>
    ''' <param name="song">The song to add to the database.</param>
    ''' <returns>The long file name of the song added to the database.</returns>
    Public Function AddSong(ByVal song As SongItem) As String

        If song.Categories.Count = 0 Then Throw New Exception("The song must be assigned at least one category.")

        ' Create the row for the song in the XML database
        Dim SongID As Guid = Guid.NewGuid
        FSongsData.AddSongsRow(SongID, song.Title, Nothing)

        ' Add song categories
        For Each CategoryID As Guid In song.Categories
            FCategoriesData.AddSongCategoriesRow(FDatabase.Songs.FSongsData.FindBySongID(SongID), _
                                                 FDatabase.Categories.FCategoriesData.FindByCategoryID(CategoryID))
        Next

        ' Save the database
        FDatabase.Save()

        ' Save the song
        song.SongID = SongID
        Dim SongFileName As String = GetSongFilename(SongID)
        song.Save(SongFileName)

        Return SongFileName

    End Function

    ''' <summary>
    ''' Edits the song in the song database.
    ''' </summary>
    ''' <param name="songID">The song ID.</param>
    ''' <param name="song">The newer version of the song. The song is updated in the database.</param>
    Public Sub EditSong(ByVal songID As Guid, ByVal song As SongItem)

        ' Perform some internal checks
        If song.SongID <> songID Then Throw New ApplicationException("A song is being edited but an invalid song ID was provided.")
        If song.Categories.Count = 0 Then Throw New Exception("The song must be assigned at least one category.")

        ' Modify the song row
        Dim Row As Data.SongsRow = FSongsData.FindBySongID(songID)
        Row.Title = song.Title

        ' Delete old categories
        Dim CategoriesToDelete As New List(Of Data.SongCategoriesRow)
        For Each CategoryRow As Data.SongCategoriesRow In FCategoriesData
            If CategoryRow.SongID = songID Then CategoriesToDelete.Add(CategoryRow)
        Next
        For Each CategoryRow As Data.SongCategoriesRow In CategoriesToDelete
            CategoryRow.Delete()
        Next
        FCategoriesData.AcceptChanges()

        ' Add new categories
        For Each CategoryID As Guid In song.Categories
            FCategoriesData.AddSongCategoriesRow(FDatabase.Songs.FSongsData.FindBySongID(songID), _
                                                 FDatabase.Categories.FCategoriesData.FindByCategoryID(CategoryID))
        Next

        ' Save the database
        FDatabase.Save()

        ' Save the song
        song.Save(GetSongFilename(songID))

    End Sub

    ''' <summary>
    ''' Deletes the given song from the database.
    ''' </summary>
    ''' <param name="song">The song to delete.</param>
    Public Sub DeleteSong(ByVal song As SongItem)
        DeleteSong(song.SongID)
    End Sub

    ''' <summary>
    ''' Deletes the song from the database.
    ''' </summary>
    ''' <param name="songID">The song ID of the song to delete.</param>
    Public Sub DeleteSong(ByVal songID As Guid)

        ' Delete the song file
        IO.File.Delete(GetSongFilename(songID))

        ' Remove the row from the songs table
        FSongsData.RemoveSongsRow(FSongsData.FindBySongID(songID))

        ' Remove song categories
        For Each Category As Data.SongCategoriesRow In FCategoriesData
            If Category.RowState <> DataRowState.Deleted Then
                If Category.SongID = songID Then Category.Delete()
            End If
        Next
        FCategoriesData.AcceptChanges()

        ' Save the XML database
        FDatabase.Save()

    End Sub

    Private Function GetSongFilename(ByVal songID As Guid) As String
        Return FDatabase.Location + "\" + songID.ToString + ".song"
    End Function

    Private Sub AddCategoriesToSong(ByVal song As SongItem)

        For Each Category As Data.SongCategoriesRow In FCategoriesData
            If Category.SongID = song.SongID Then
                song.Categories.Add(Category.CategoryID)
            End If
        Next

    End Sub

    Friend Sub AddCategoryToSong(ByVal songID As Guid, ByVal categoryID As Guid)

        FCategoriesData.AddSongCategoriesRow(FSongsData.FindBySongID(songID), _
                                             FDatabase.Categories.FCategoriesData.FindByCategoryID(categoryID))

    End Sub

    ''' <summary>
    ''' Gets the license associated with the given song.
    ''' </summary>
    ''' <param name="songID">The ID of the song whose associated license to return.</param>
    ''' <returns>The license associated with the given song, or null if there is no license associated with the song.</returns>
    Function GetSongLicense(ByVal songID As Guid) As License

        ' Find the license
        Dim Row As Data.SongsRow = FSongsData.FindBySongID(songID)
        If Row IsNot Nothing Then
            If FDatabase.Licenses.DoesLicenseExist(Row.LicenseID) Then
                Return FDatabase.Licenses.GetLicense(Row.LicenseID)
            End If
        End If

        ' The license could not be found
        Return Nothing

    End Function

End Class
